#!/bin/sh

FWM_X86APP_DIR="/mnt/usr"
FWM_CONFIG_DIR="/mnt/usr/.config"
FWM_UPGRADE_DIR="/mnt/usr/.upgrade"
FWM_SHX_FLAG="${FWM_CONFIG_DIR}/.fwm_dbg_shx"

###########################################################
#             DEFINE FILES AND VARIABLES
#
#
###########################################################

#if [ -e $FWM_SHX_FLAG ] ; then
  set -x
#fi

APPFS_PATH="${FWM_X86APP_DIR}/appfs"

FWM_INSTALLING="${FWM_UPGRADE_DIR}/.installing"
FWM_INSTALLED="${FWM_UPGRADE_DIR}/installed"

FWM_FACTORY_RESET="${FWM_X86APP_DIR}/.factory_reset"
FWM_UPGRADE_OK="${FWM_X86APP_DIR}/.upgrade_ok"
FWM_UPGRADE_NOK="${FWM_X86APP_DIR}/.upgrade_nok"

FWM_KERNEL_UPG_FLAG="upgrade_kernel"
FWM_KERNEL_IMG_NAME="kernel-ext2.img"
FWM_KERNEL_IMG_MD5SUM="${FWM_KERNEL_IMG_NAME}.md5sum"

FWM_ROOTFS_UPG_FLAG="upgrade_rootfs"
FWM_ROOTFS_IMG_NAME="rootfs-squashfs.img"
FWM_ROOTFS_IMG_MD5SUM="${FWM_ROOTFS_IMG_NAME}.md5sum"

FWM_X86IMG_UPG_FLAG="upgrade_x86img"
FWM_X86IMG_IMG_NAME="openwrt-x86-generic-combined-squashfs.img"
FWM_X86IMG_IMG_MD5SUM="${FWM_X86IMG_IMG_NAME}.md5sum"

FWM_X86APP_UPG_FLAG="upgrade_x86app"
FWM_X86APP_IMG_NAME="x86proj_1.0-1.ipk"
FWM_X86APP_IMG_MD5SUM="${FWM_X86APP_IMG_NAME}.md5sum"

FWM_PKG_VERSION_FILE="version.txt"

FWM_PKG_NAME="x86_pkg.tar.gz"
FWM_PKG_MD5SUM="${FWM_PKG_NAME}.md5sum"

# persistent info
FWM_P_DIR="${FWM_CONFIG_DIR}/.fwm/"
FWM_P_DELIM=":"
FWM_P_STATE_PREFIX=${FWM_P_DIR}fwm${FWM_P_DELIM}
# state info
STATE_IDLE="IDLE"
STATE_LOADED="LOADED"
STATE_INSTALLED="INSTALLED"
# operations
OP_DOWNLOAD="download"
OP_INSTALL="install"
# tmpfs files/flags
FWM_T_TMPFS_DIR="/tmp/.fwm/"
FWM_T_CMD_IN_PROGRESS_FILE="${FWM_T_TMPFS_DIR}.cmd_in_progress"
FWM_T_SHELL_STDERR="${FWM_T_TMPFS_DIR}.fwm_shell_stderr"
FWM_T_REBOOT_INFO="${FWM_T_TMPFS_DIR}.reboot.info"
# download dir
FWM_SDS="/mnt/usr/sds"
MD5SUM="`which md5sum`"
# upgrade type
FWM_UPGRADE_TDD="upgrade_tdd"
FWM_UPGRADE_FDD="upgrade_fdd"
FWM_UPGRADE_ALL_BASEBANE="upgrade_baseband"
FWM_UPGRADE_ALL="upgrade_all"
FWM_UPGRADE_GSM="upgrade_gsm"
FWM_FDD_IMG="lte_fddzm.img"
FWM_TDD_IMG="lte_tddzm.img"
FWM_GSM_IMG="gsmRelease.tar"
FWM_TFTP_DIR="/tftpboot"


###########################################################
#                     FUNCTIONS
###########################################################

###########################################################
#  ENV
###########################################################

###########################################################
#  Logging
###########################################################
INFO_LOG () 
{
  logger -p local0.notice $LOGGER_V -t fwm **INFO** "$*"
}
CRIT_LOG () 
{
  logger -p local0.crit $LOGGER_V -t fwm **CRITICAL** "$*"
}
ERR_LOG () 
{
  logger -p local0.err $LOGGER_V -t fwm **ERROR** "$*"
}
###########################################################
#  Shell command wrappers - mainly used to log errors
###########################################################
SHELL_ERR_LOG()
{
  output=`$1 2>&1`
  local rc=$?
  if [ $rc -ne 0 ]; then
    ERR_LOG $1 "command output: ($output), command rc ($rc)"
  fi
  return $rc
}
SHELL_CRIT_LOG()
{
  output=`$1 2>&1`
  local rc=$?
  if [ $rc -ne 0 ]; then
    CRIT_LOG $1 "command output: ($output), command rc ($rc)"
  fi
  return $rc
}

###########################################################
#  Wrap all responses in wrappers in order to support machine-to-machine (MMI)
#  interface where all comments need to be encapsulated in a XML response.
###########################################################
do_echo()
{
  # deal with XML later
  echo $*
}
clean_sds()
{
  if [ -d  $FWM_SDS ]; then
    SHELL_CRIT_LOG "rm -fr $FWM_SDS"
  fi
}
clean_tftpboot()
{
  if [ -d $FWM_TFTP_DIR ]; then
     SHELL_CRIT_LOG "rm $FWM_TFTP_DIR/*"
  fi
}
clean_tmp_files()
{
  clean_sds
  if [ -d $FWM_T_TMPFS_DIR ]; then  
    rm -Rf $FWM_T_TMPFS_DIR
  fi
}
exit_success()
{
  clean_tmp_files
  exit 0
}
exit_failure()
{
  if [ "$1" != "noclean" ] ; then 
    clean_tmp_files
    if [ "$1" != "" ]; then
      do_echo "$*"
    fi
  fi
  exit 1
}
###########################################################
#  FWM persistent information
# 
#  FWM stores persistent information on the system in order to keep track of
#  the following:
#    * current state (IDLE|LOADED|INSTALLED)
#    * expected active zone (0|1)
#
#  The file name format is: ${FWM_P_STATE_PREFIX}:state:zone
# 
#  The file is always of size 0, the file name is used to "store" the states.
#
#  The integrity of the persistent data is ensured while writing since a file 
#  rename is an atomic operation.
#
###########################################################
validate_persistent_data()
{ 
  if [ ! -d $FWM_P_DIR ]; then
    SHELL_CRIT_LOG "mkdir $FWM_P_DIR"
  fi
  ls ${FWM_P_STATE_PREFIX}* > /dev/null 2>&1
  if [ $? -ne 0 ]; then
    local default_pdata="${FWM_P_STATE_PREFIX}${STATE_IDLE}"
    INFO_LOG "persistent data not present, creating default $default_pdata"
    SHELL_CRIT_LOG "touch $default_pdata"
  fi
  validate_persistent_state
}
validate_persistent_state()
{
  P_STATE="`ls ${FWM_P_STATE_PREFIX}* | cut -d $FWM_P_DELIM -f 2`"
  if [ "$P_STATE" != "$STATE_IDLE" ]      &&
     [ "$P_STATE" != "$STATE_LOADED" ]    &&
     [ "$P_STATE" != "$STATE_INSTALLED" ]; then
    #reset to IDLE
    ERR_LOG "invalid persistent state ($P_STATE), reset to $STATE_IDLE"
    P_STATE=$STATE_IDLE
  fi
}
set_persistent_data()
{
  local current_pdata=`ls ${FWM_P_STATE_PREFIX}*`
  local updated_pdata="${FWM_P_STATE_PREFIX}${P_STATE}"
  if [ "$current_pdata" != "$updated_pdata" ]; then
    INFO_LOG "updating persistent data from $current_pdata to $updated_pdata"
    SHELL_CRIT_LOG "mv $current_pdata $updated_pdata"
    SHELL_CRIT_LOG "sync"
  fi
}
###########################################################
#  User responses
###########################################################
validate_state_transition()
{
  if [ -r $FWM_T_CMD_IN_PROGRESS_FILE ]; then
    do_echo "software `cat $FWM_T_CMD_IN_PROGRESS_FILE` in progress"
    exit_failure "noclean"
  fi

  if [ $IGNORE_FWM_STATE != "1" ] ; then
    #Based on state machine diagram
    if [ "$OPERATION" = "$OP_DOWNLOAD" ] || [ "$OPERATION" = "$OP_INSTALL" ]; then
      if [ "$P_STATE" = "$STATE_INSTALLED" ]; then
        exit_failure "\"$OP_DOWNLOAD\" can only be done from \"$STATE_IDLE\" or \"$STATE_LOADED\" states"
      fi
    fi 
  fi  

  SHELL_ERR_LOG "`echo $OPERATION > $FWM_T_CMD_IN_PROGRESS_FILE`"

  if [ "$OPERATION" = "$OP_DOWNLOAD" ]; then
      download
  elif [ "$OPERATION" = "$OP_INSTALL" ]; then
      install
  else
    ERR_LOG "Invalid operation"
    SHELL_ERR_LOG "`echo NOOP > $FWM_T_CMD_IN_PROGRESS_FILE`"
    exit_success
  fi  
}

fwm_reboot_prepare()
{
  SHELL_CRIT_LOG "`echo "prepare to reboot" > ${FWM_T_REBOOT_INFO}`"
  local i=0
  local res=""
  while true ; do
    res="`cat ${FWM_T_REBOOT_INFO}`"
    if [ "$res" = "OK" ] ; then
      SHELL_CRIT_LOG "`rm -f ${FWM_T_REBOOT_INFO}`"
      return
    fi
    if [ $i -gt 30 ] ; then
      SHELL_CRIT_LOG "`rm -f ${FWM_T_REBOOT_INFO}`"
      return
    fi
    i=$(($i+1))
    sleep 1
  done
}
###########################################################
#  reboot
###########################################################
fwm_reboot()
{
  do_echo "Rebooting."
  fwm_reboot_prepare
} 

###########################################################
#  Swap directories
###########################################################
erase_appfs()
{
  SHELL_CRIT_LOG "rm -Rf ${APPFS_PATH}/*"
  SHELL_CRIT_LOG "mkdir -p ${APPFS_PATH}/pkg"
  SHELL_CRIT_LOG "sync"
}

###########################################################
#  Operations
###########################################################

###########################################################
#  download operation (TRANSITION_2, TRANSITION_9)
#
#  - download file using wget
#
###########################################################
download()
{
  local md5sum=""

  # clean sds in case previous download failed and cleanup was not done properly.
  clean_sds
  clean_tftpboot 
  SHELL_ERR_LOG "mkdir -p $FWM_SDS"
  cd $FWM_SDS


  while [ 1 ] ;
  do 
    wget -c -t 10 -T 5 $PKG_URL 2>$FWM_T_SHELL_STDERR
    if [ $? -eq 0 ] ; then
      INFO_LOG  "down load file success"
      break;
    fi
    sleep 2
  done
#  md5sum="`$MD5SUM $FWM_SDS/$FWM_PKG_NAME |awk '{print $1}'`"
#  if [ "$md5sum" = "$PKG_MD5SUM" ]; then
    install
#  else
 #   exit_failure "md5sum_mismatch"
#  fi
}

###########################################################
#  install x86 ipk
#
#
#
###########################################################
installIpk()
{
    SHELL_CRIT_LOG "touch $FWM_INSTALLING"
    SHELL_CRIT_LOG "rm $FWM_UPGRADE_DIR/*"
    SHELL_CRIT_LOG  "cp $FWM_X86APP_DIR/appfs/pkg/*.ipk  $FWM_UPGRADE_DIR/"
    ipkList=`ls -l $FWM_X86APP_DIR/appfs/pkg/ |grep 'ipk$' | awk '{print $9}'`
    for i in $ipkList
    do
      if [ -f $FWM_X86APP_DIR/appfs/pkg/$i.md5sum ]; then
        md5sum1=`cat $FWM_X86APP_DIR/appfs/pkg/$i.md5sum |awk '{print $1}'`
        md5sum2=`md5sum $FWM_X86APP_DIR/appfs/pkg/$i |awk '{print $1}'`
        if [ $md5sum1 = $md5sum2 ]; then
          opkg --force-overwrite install $FWM_X86APP_DIR/appfs/pkg/$i > /dev/null 2>$FWM_T_SHELL_STDERR
          if [ $? -ne 0 ]; then
            CRIT_LOG "unable install x86app (`cat $FWM_T_SHELL_STDERR`)"
            SHELL_CRIT_LOG "rm $FWM_INSTALLING"      
            exit_failure "write_x86app_failed"
          fi
        else
          exit_failure "md5sum_mismatch"
        fi
      fi  
    done
    SHELL_CRIT_LOG "rm $FWM_INSTALLING" 
    SHELL_CRIT_LOG "sync"

  #set state / persistent file
    P_STATE=$STATE_INSTALLED
    set_persistent_data

  # set upgrade ok flag
    touch $FWM_UPGRADE_OK

    echo done
    exit 0
}

###########################################################
#  install operation
#
#  install a given package:
#
###########################################################
install()
{
  erase_appfs

  # create dirs
  local DEST="$FWM_X86APP_DIR/appfs/pkg"
  if [ ! -e $DEST ] ; then
      SHELL_CRIT_LOG "mkdir -p $DEST"
  fi
  cd $DEST
  FWM_PKG_NAME=`ls -l $FWM_SDS |awk '{print $9}'`
  if [ ! -f "$FWM_SDS/$FWM_PKG_NAME" ] ; then
    exit_failure "pkg_not_exist"
  fi

  tar zxvf $FWM_SDS/$FWM_PKG_NAME > /dev/null 2>&1
  if [ $? -ne 0 ]; then
    CRIT_LOG "tar decompress failed ($?)"
    exit_failure "pkg_decompress_failed"
  fi

  if [ -f "$FWM_X86APP_DIR/appfs/pkg/$FWM_UPGRADE_GSM" ] ; then
      SHELL_CRIT_LOG "cp $FWM_X86APP_DIR/appfs/pkg/* $FWM_TFTP_DIR"
      SHELL_CRIT_LOG "rm -fr $FWM_T_CMD_IN_PROGRESS_FILE"
      echo "upgradeGSM"
      exit 0
  fi


  if [ -f "$FWM_X86APP_DIR/appfs/pkg/$FWM_UPGRADE_TDD" ] ; then
      SHELL_CRIT_LOG "cp $FWM_X86APP_DIR/appfs/pkg/* $FWM_TFTP_DIR"
      SHELL_CRIT_LOG "rm -fr $FWM_T_CMD_IN_PROGRESS_FILE"
      echo "upgradeTDD"
      exit 0
  fi

  if [ -f "$FWM_X86APP_DIR/appfs/pkg/$FWM_UPGRADE_FDD" ] ; then
      SHELL_CRIT_LOG "cp $FWM_X86APP_DIR/appfs/pkg/* $FWM_TFTP_DIR"
      SHELL_CRIT_LOG "rm -fr $FWM_T_CMD_IN_PROGRESS_FILE"
      echo "upgradeFDD"
      exit 0
  fi

  if [ -f "$FWM_X86APP_DIR/appfs/pkg/$FWM_UPGRADE_ALL_BASEBANE" ] ; then
      SHELL_CRIT_LOG "cp $FWM_X86APP_DIR/appfs/pkg/* $FWM_TFTP_DIR"
      SHELL_CRIT_LOG "rm -fr $FWM_T_CMD_IN_PROGRESS_FILE"
      echo "upgradeAllBaseband"
      exit 0
  fi

  if [ -f "$FWM_X86APP_DIR/appfs/pkg/$FWM_UPGRADE_ALL" ] ; then
      SHELL_CRIT_LOG "cp $FWM_X86APP_DIR/appfs/pkg/lte*  $FWM_TFTP_DIR"
      SHELL_CRIT_LOG "rm -fr $FWM_T_CMD_IN_PROGRESS_FILE"
      ls -l $FWM_X86APP_DIR/appfs/pkg/*.ipk > /dev/null
      if [ $? -eq 0 ] ; then
        if [ -f  "$FWM_X86APP_DIR/appfs/pkg/$FWM_FDD_IMG" -a -f  "$FWM_X86APP_DIR/appfs/pkg/$FWM_TDD_IMG" ]; then
          echo "upgradeAll"
          exit 0
        fi
        if [ -f "$FWM_X86APP_DIR/appfs/pkg/$FWM_FDD_IMG" ]; then
          echo "upgradex86AndFdd"
          exit 0
        fi 
        if [ -f "$FWM_X86APP_DIR/appfs/pkg/$FWM_TDD_IMG" ]; then
          echo "upgradex86AndTdd"
          exit 0
        fi
        installIpk
      else
        if [ -f  "$FWM_X86APP_DIR/appfs/pkg/$FWM_FDD_IMG" -a -f  "$FWM_X86APP_DIR/appfs/pkg/$FWM_TDD_IMG" ]; then
          echo "upgradeAllBaseband"
          exit 0
        fi        
        if [ -f "$FWM_X86APP_DIR/appfs/pkg/$FWM_FDD_IMG" ]; then
          echo "upgradeFDD"
          exit 0
        fi 
        if [ -f "$FWM_X86APP_DIR/appfs/pkg/$FWM_TDD_IMG" ]; then
          echo "upgradeTDD"
          exit 0
        fi
      fi
  fi

  if [ -f "$FWM_KERNEL_UPG_FLAG" ] ; then
    dd if=$FWM_X86APP_DIR/appfs/pkg/$FWM_KERNEL_IMG_NAME of=/dev/sda1 > /dev/null 2>$FWM_T_SHELL_STDERR
    if [ $? -ne 0 ]; then
      CRIT_LOG "unable dd kernel (`cat $FWM_T_SHELL_STDERR`)"
      exit_failure "write_kernel_failed"
    fi
  fi

  if [ -f "$FWM_ROOTFS_UPG_FLAG" ] ; then
    dd if=$FWM_X86APP_DIR/appfs/pkg/$FWM_ROOTFS_IMG_NAME of=/dev/sda2 > /dev/null 2>$FWM_T_SHELL_STDERR
    if [ $? -ne 0 ]; then
      CRIT_LOG "unable dd rootfs (`cat $FWM_T_SHELL_STDERR`)"
      exit_failure "write_rootfs_failed"
    fi
  fi

  if [ -f "$FWM_X86IMG_UPG_FLAG" ] ; then
    md5sum3=`cat $FWM_X86APP_DIR/appfs/pkg/$FWM_X86IMG_IMG_MD5SUM |awk '{print $1}'`
    md5sum4=`md5sum $FWM_X86APP_DIR/appfs/pkg/$FWM_X86IMG_IMG_NAME |awk '{print $1}'`
    if [ $md5sum3 = $md5sum4 ]; then
		cp /etc/config/network	/mnt/usr/
        dd if=$FWM_X86APP_DIR/appfs/pkg/$FWM_X86IMG_IMG_NAME of=/dev/sda > /dev/null 2>$FWM_T_SHELL_STDERR
        if [ $? -ne 0 ]; then
            CRIT_LOG "unable dd rootfs (`cat $FWM_T_SHELL_STDERR`)"
        exit_failure "write_img_failed"
        fi
	#cp /mnt/usr/network	/etc/config/network
    else
        exit_failure "md5sum_mismatch"
    fi
  fi

  if [ -f "$FWM_X86APP_UPG_FLAG" ] ; then
     installIpk
  fi

  SHELL_CRIT_LOG "sync"

  #set state / persistent file
  P_STATE=$STATE_INSTALLED
  set_persistent_data

  # set upgrade ok flag
  touch $FWM_UPGRADE_OK

  echo done
  exit 0
}

###########################################################
#  factory reset operation
#
#  restore factory setting:
#
###########################################################
factory_reset()
{
  cp /mnt/config/dev_config.xml /mnt/usr
  rm -rf /overlay/*
  touch $FWM_FACTORY_RESET

  echo done
  exit 0
}

###########################################################
#  initialize
#
#  - called from init script
#  - raises strikeout related alarms.
#
# This function *MUST* call "exit X" and NOT exit_success or exit_failure
###########################################################
initialize()
{
  validate_persistent_data

  # At this point in init the following are not required and are
  # removed, so that user commands can be issued without problems.
  if [ -d $FWM_T_TMPFS_DIR ] ; then
    rm -R $FWM_T_TMPFS_DIR
  fi

  if [ -f $FWM_FACTORY_RESET ] ; then
    rm -fr $FWM_FACTORY_RESET > /dev/null 2>&1
    rm -fr $FWM_X86APP_DIR/*  > /dev/null 2>&1
    mv /mnt/usr/dev_config.xml /mnt/config/dev_config.xml > /dev/null 2>&1
  fi
  # this function must exit with exit 0
  exit 0  
}

###########################################################
#  Deal with aborted operations
#
#  TODO
# - this will be implemented later, ctlr -c is not customer supported
###########################################################
query()
{
  if [ "$1" = "state" ]; then
    validate_persistent_data
    echo -n "$P_STATE"
  elif [ "$1" = "command" ]; then
    if [ -e "$FWM_T_CMD_IN_PROGRESS_FILE" ]; then
      echo -n "`cat $FWM_T_CMD_IN_PROGRESS_FILE`"
    else
      echo -n "none"
    fi
  else
    # this function should call exit directly
    exit 1
  fi
}
query_basic()
{
  validate_persistent_data
  echo "FWM State: $P_STATE" 
}
print_help()
{
  do_echo "Usage: fwm [OPTIONS]"
  do_echo ""
  do_echo "OPTIONS:"
  do_echo " -d <version> download remote pkg over http"
  do_echo " -i <package> install package locally accessible"
  do_echo " -l ignore FWM state"
  do_echo " -m md5 checksum"
  do_echo " -n pkg name"
  do_echo " -q query - used programatically"
  do_echo " -Q query summary"
  do_echo " -r reboot"
  do_echo " -v verbose"
  do_echo " -w reset FWM persistent database to defaults"
  do_echo " -X debug verbose output"
  do_echo " -z initialize"
  do_echo " -h help"

  exit_failure
}

###########################################################
#                      MAIN
###########################################################
OPERATION=""
VERBOSE="0"
PKG_URL=""
PKG_FILE=""
PKG_MD5SUM=""
IGNORE_FWM_STATE="0"
HW_VERSION="V1"

INFO_LOG "fwm.sh $*"

if [ $# -eq 0 ]; then
  print_help
fi

if [ -d $FWM_CONFIG_DIR ]; then
  rm -fr $FWM_CONFIG_DIR
fi

if [ ! -d $FWM_CONFIG_DIR ]; then
  mkdir $FWM_CONFIG_DIR
fi

if [ ! -d $FWM_UPGRADE_DIR ]; then
  mkdir $FWM_UPGRADE_DIR
fi

if [ ! -d $FWM_T_TMPFS_DIR ] ; then
  mkdir $FWM_T_TMPFS_DIR
fi

while getopts d:fhi:Ilm:n:q:QrvwXz opt
do
   case "$opt" in
      d) OPERATION=$OP_DOWNLOAD;PKG_URL=$OPTARG;;
      f) factory_reset;;
      h) print_help;;
      i) OPERATION=$OP_INSTALL;PKG_FILE=$OPTARG;;
      I) installIpk;;
      l) IGNORE_FWM_STATE="1";;
      m) PKG_MD5SUM=$OPTARG;;
      n) FWM_PKG_NAME=$OPTARG;;
      q) query $OPTARG;exit 0;;
      Q) query_basic;exit 0;;
      r) sync;reboot -f;exit 0;;
      v) VERBOSE="1";;
      w) P_STATE=$STATE_IDLE;set_persistent_data;exit 0;;
      X) set -x;;
      z) initialize;;
      \?) print_help;;
   esac
done

if [ "$VERBOSE" = "1" ] ; then
    LOGGER_V=-s
else
    LOGGER_V=
fi

# set persistent data
validate_persistent_data

validate_state_transition

exit_success
